<script setup lang="ts">
import { computed, onMounted, onUnmounted } from "vue";
import AMapLoader from "@amap/amap-jsapi-loader";
import { AMAP_MAP_KEY, AMAP_SECRET_KEY } from "./config";
import type { PolylineOption, PluginName, MapOptions, PolylineInstance, AmapModule, PolylineMethods } from "./interface";

/**
 * 组件Props接口
 * @property plugins - 需要加载的插件列表
 * @property opts - 地图配置选项
 */
export interface Props {
  plugins?: PluginName[];
  opts?: MapOptions;
}

// 设置Props默认值
const props = withDefaults(defineProps<Props>(), {
  plugins: () => ["Scale", "ToolBar"],
  opts: () => ({
    zoom: 12,
    center: [114.525918, 38.032612]
  })
});

/**
 * 扩展Window接口以支持AMap安全配置
 */
interface ExtendsWindow extends Window {
  _AMapSecurityConfig?: {
    securityJsCode: string;
  };
}
let _window: ExtendsWindow = window;

// 定义map实例
let map: any = null;
let AMap: any = null;
let polylineInstances: PolylineInstance[] = [];

/**
 * 组件挂载时初始化地图
 */
onMounted(() => {
  initMap();
});

/**
 * 组件卸载时销毁地图
 */
onUnmounted(() => {
  map?.destroy();
});

/**
 * 格式化插件名称，添加AMap.前缀
 * @returns {string[]} 格式化后的插件名称数组
 */
const formattedPlugins = computed(() => {
  return props.plugins.map(plugin => `AMap.${plugin}`);
});

/**
 * 初始化地图
 * @async
 * @returns {Promise<void>}
 */
const initMap = async () => {
  // 设置AMap安全配置
  _window._AMapSecurityConfig = {
    securityJsCode: AMAP_SECRET_KEY
  };
  AMapLoader.load({
    key: AMAP_MAP_KEY, // 申请好的Web端开发者Key，首次调用 load 时必填
    version: "2.0" // 指定要加载的 JSAPI 的版本，缺省时默认为 1.4.15
  })
    .then(m => {
      AMap = m;
      // 创建地图实例
      map = new AMap.Map("container", {
        zoom: props.opts.zoom, // 初始化地图级别
        center: props.opts.center // 初始化地图中心点位置
      });

      // 加载插件
      AMap.plugin(formattedPlugins.value, () => {
        props.plugins.forEach(plugin => {
          map.addControl(new AMap[plugin]());
        });
      });
    })
    .catch(e => {
      console.log(e);
    });
};

/**
 * 绘制多条轨迹线
 * @param {PolylineOption[]} polylineOptions - 折线配置数组
 * @returns {Promise<AmapModule>} 返回包含折线实例的模块对象
 */
const drawPolylines = async (polylineOptions: PolylineOption[]): Promise<AmapModule> => {
  // 验证AMap实例
  if (!AMap) {
    console.warn("初始化地图失败");
    return createEmptyAmapModule();
  }
  // 验证参数类型
  if (!Array.isArray(polylineOptions)) {
    console.warn("Polyline模块: 参数必须是折线配置数组");
    return createEmptyAmapModule();
  }

  try {
    // 加载动画插件
    await loadMoveAnimationPlugin();

    // 清除现有折线
    removePolylines();

    // 创建所有折线实例
    polylineInstances = await createAllPolylines(polylineOptions);

    return {
      name: "Polyline",
      instance: polylineInstances,
      events: { remove: removePolylines.bind(this) }
    };
  } catch (error) {
    console.error("绘制折线失败:", error);
    return createEmptyAmapModule();
  }
};

/**
 * 创建空AmapModule对象
 * @returns {AmapModule} 空模块对象
 */
const createEmptyAmapModule = (): AmapModule => ({
  name: "Polyline",
  instance: [],
  events: {}
});

/**
 * 加载移动动画插件
 * @returns {Promise<void>}
 */
const loadMoveAnimationPlugin = (): Promise<void> => {
  return new Promise((resolve, reject) => {
    AMap.plugin("AMap.MoveAnimation", err => {
      if (err) reject(err);
      else resolve();
    });
  });
};

/**
 * 创建所有折线实例
 * @param {PolylineOption[]} options - 折线配置数组
 * @returns {Promise<PolylineInstance[]>} 折线实例数组
 */
const createAllPolylines = async (options: PolylineOption[]): Promise<PolylineInstance[]> => {
  return Promise.resolve(options.map(option => createSinglePolyline(option)).filter(Boolean) as PolylineInstance[]);
};

/**
 * 创建单条轨迹线
 * @param {PolylineOption} option - 折线配置
 * @returns {PolylineInstance | null} 返回折线实例或null
 */
const createSinglePolyline = (option: PolylineOption): PolylineInstance | null => {
  if (!option.path || option.path.length === 0) return null;

  // 创建标记点
  const marker = new AMap.Marker({
    map,
    position: option.path[0] || [],
    icon: "https://a.amap.com/jsapi_demos/static/demo-center-v2/car.png",
    offset: new AMap.Pixel(-13, -26)
  });

  // 创建折线
  const polyline = new AMap.Polyline({
    ...option,
    map
  });

  // 创建已通过路径的折线
  const passedPolyline = new AMap.Polyline({
    ...option,
    strokeColor: "#AF5",
    strokeWeight: option.strokeWeight,
    map
  });

  // 标记点移动事件
  marker.on("moving", (e: any) => {
    passedPolyline.setPath(e.passedPath);
    map.setCenter(e.target.getPosition(), true);
  });

  // 调整视图以适应路径
  map.setFitView();

  // 绑定折线控制方法
  const methods = bindPolylineEvents(marker, option.path);

  return {
    polyline,
    passedPolyline,
    marker,
    methods
  };
};

/**
 * 绑定折线控制事件
 * @param {any} marker - 标记点实例
 * @param {[number, number][]} path - 路径坐标数组
 * @returns {PolylineMethods} 返回折线控制方法
 */
const bindPolylineEvents = (marker: any, path: [number, number][]): PolylineMethods => {
  return {
    /**
     * 开始动画
     * @param {number} [duration=500] - 动画持续时间(毫秒)
     */
    start: (duration = 500) => {
      marker.moveAlong(path, {
        duration,
        autoRotation: true
      });
    },
    /** 暂停动画 */
    pause: () => {
      marker.pauseMove();
    },
    /** 恢复动画 */
    resume: () => {
      marker.resumeMove();
    },
    /** 停止动画 */
    stop: () => {
      marker.stopMove();
    }
  };
};

/**
 * 移除所有折线
 * @returns {void}
 */
const removePolylines = (): void => {
  if (!map) return;

  // 清除所有覆盖物
  map.clearMap();

  // 同时清理polylineInstances数组
  if (polylineInstances) {
    polylineInstances.forEach(item => {
      item.marker.stopMove();
    });
    polylineInstances = [];
  }
};

// 暴露组件方法
defineExpose({
  drawPolylines,
  createSinglePolyline,
  removePolylines
});
</script>

<template>
  <div class="map-container">
    <div id="container"></div>
  </div>
</template>

<style lang="scss" scoped>
.map-container {
  position: relative;
  width: 100%;
  height: 100%;
  padding: 0 !important;
  margin: 0 !important;
}
#container {
  width: 100%;
  height: 100%;
}
</style>
